#include "map_collect.h"
#include "public_define.h"
#include "tool.h"
#include "busesp.pb.h"
#include "common_opr_all.h"
#include "data_cache.h"
#include "ins_data.pb.h"
#include "busesp.pb.h"
#include "adr_trigger.h"

#include <dirent.h>

using namespace DcAdr;


/*
todo:
0.1000 2001一直在围栏，每5分钟分包上传
1.1000和2001分包采？怎么触发
2.地图配置缓存文件策略
*/

MapCollect::MapCollect(/* args */)
{
    factory = geos::geom::GeometryFactory::create();
    readerPoint = new geos::io::WKTReader(*factory);
}

MapCollect::~MapCollect()
{
    if (readerPoint != nullptr)
    {
        delete readerPoint;
    }
}

MapCollect &MapCollect::getInstance()
{
    static MapCollect instance;
    return instance;
}

bool MapCollect::saveConfig(const std::string &confCloud)
{
    bool ret = false;

    Json::Reader reader;
    Json::Value root;
    if (reader.parse(confCloud, root) && root.isMember("data") && root["data"].isMember("fences"))
    {
        std::string writeStr = root["data"]["fences"].toStyledString();
        Log_Info("map config: {}", writeStr);

        //众包地图配置，保存到本地
        std::ofstream osMap;
        osMap.open(global_data::g_config_map_path);
        if (!osMap.is_open())
        {
            Log_Info("file open failed, g_config_map_path : {}", global_data::g_config_map_path);
        }
        osMap << writeStr;
        osMap.close();
        Log_Info("[CollectConfig] get server config success;write to:{} success", global_data::g_config_map_path);

        ret = true;
        //众包地图配置，保存到/map目录，供csmap用
        {
            std::ofstream osCsmap;
            string mapadrPath = "/map/csmap/adr_fences.conf";
            osCsmap.open(mapadrPath);
            if (!osCsmap.is_open())
            {
                Log_Info("file open failed, {}", mapadrPath);
            }
            osCsmap << writeStr;
            osCsmap.close();
            Log_Info("[CollectConfig] get server config success;write to:{} success", mapadrPath);
        }
    }
    else
    {
        Log_Info("have no map config");
    }

    return ret;
}

//某个围栏采集成功，删除此围栏配置
bool MapCollect::deletFenceConfig(const std::string &fenceId)
{
    bool ret = false;
    string jsonString;
    // 读取配置文件内容
    CommonOprSystem::readFileAllOnce(global_data::g_config_map_path, jsonString);

    if (jsonString.empty())
    {
        return ret;
    }

    CommonOprJson::jsonstrformat(jsonString);
    Json::Reader reader;
    Json::Value root;
    Json::Value rootNew;
    //解析不成功或者根节点不是数组就有问题
    if ((reader.parse(jsonString, root)) && (root.isArray())) 
    {
        for (int i = 0; i < root.size(); ++i)
        {
            string confId = JsonToValue<std::string>(root[i]["id"]);
            if ((fenceId.compare(confId)))//不是这个围栏赋值，只取消这个围栏
            {
                rootNew.append(root[i]);
            }
        }

        std::string newDesen;
        if (rootNew.empty())
        {
        }
        else
        {
            newDesen = rootNew.toStyledString();
        }

        Log_Info("zhongbao config: {}", newDesen);

        CommonOprSystem::writeStringBuffToFile(global_data::g_config_map_path, newDesen);
        ret = true;
    }
    else
    {
        Log_Info("[FileReupload][readReuploadFileJson] json parse error! jsonString: {}", jsonString);
    }   

    return ret;
}

bool MapCollect::parseMapConfigJsonData(const std::string &fencesArrStr)
{
    Log_Info("parseMapConfigJsonData start ......");
    Json::Reader reader;
    Json::Value fencesArrJson;
    if (!reader.parse(fencesArrStr, fencesArrJson))
    {
        Log_Info("json parse error! {}", fencesArrStr);
        return false;
    }
    parseMapCollect(fencesArrJson);
    Log_Info("parseMapConfigJsonData end ......");
    return true;
}

//adr_2024-09-13_08-24-57.txt 可以查看此文件有配置格式
bool MapCollect::parseMapCollect(const Json::Value &fences)
{
    Log_Info("Parse map collect");

    if (!fences.isArray())
    {
        Log_Info("fences is not array! {}", fences.toStyledString());
        return false;
    }
    Log_Info("config fence size :{}",fences.size());

    for (int i = 0; i < fences.size(); ++i)
    {
        if (!fences[i].isMember("fenceType"))
        {
            Log_Info("fences[{}] fenceType is not exist", i);
            continue;
        }
        auto type = JsonToValue<int>(fences[i]["fenceType"]);

        if (type == 1000)//1.0围栏数据交由csmp模块自己采集，adr不再采集
        {
            continue;
        }
        
        if(NotContain_Map(m_eventFence, type))
        {
            std::vector<FenceInfo_t> nullvec;
            m_eventFence[type] = nullvec;
        }
        vector<FenceInfo_t> &v_Fences = m_eventFence[type];

        FenceInfo_t signalRuleInfo;
        signalRuleInfo.eventid = CSMAP_1;
        signalRuleInfo.hasvedio = false;
        signalRuleInfo.type = JsonToValue<int>(fences[i]["fenceType"]);

        if (fences[i].isMember("hasVideo"))
        {
            signalRuleInfo.hasvedio = JsonToValue<bool>(fences[i]["hasVideo"]);
        }
        
        switch (type)
        {
        case 2001:
		{
            signalRuleInfo.eventid = CSMAP_2;
			/*
            signalRuleInfo.collectDatas.push_back("ad_algo_ins-localization.InsData-OpenSourceDu");
            signalRuleInfo.collectDatas.push_back("encode_srv-EncodeSrv.EncodeH265-CAM0");
            signalRuleInfo.collectDatas.push_back("encode_srv-EncodeSrv.EncodeH265-CAM1");
            signalRuleInfo.collectDatas.push_back("encode_srv-EncodeSrv.EncodeH265-CAM2");
            signalRuleInfo.collectDatas.push_back("encode_srv-EncodeSrv.EncodeH265-CAM3");
            signalRuleInfo.collectDatas.push_back("encode_srv-EncodeSrv.EncodeH265-CAM8");
            signalRuleInfo.collectDatas.push_back("encode_srv-EncodeSrv.EncodeH265-CAM9");
            signalRuleInfo.collectDatas.push_back("encode_srv-EncodeSrv.EncodeH265-CAM10");
            signalRuleInfo.collectDatas.push_back("ad_algo_ego-algo.CalibParams");
			*/
			std::shared_ptr<ProtoCondInfo_t> BA625ProtoCondInfo = std::make_shared<ProtoCondInfo_t>();
			Log_Info("gd fence type normal map collect :{}",type);
			if(DcAdr::AdrTrigger::getInstance().getOneEventProtoCondInfo(CSMAP_2,BA625ProtoCondInfo))
			{
				Log_Info("gd get {} collect success:{}",CSMAP_2,type);
			}
			
			signalRuleInfo.collectDatas =BA625ProtoCondInfo->collectData;
			Log_Info("gd BA625 collect topic.size:{}",signalRuleInfo.collectDatas.size());
			//for(auto data:signalRuleInfo.collectDatas)
			//{
			//	Log_Info("gd BA625 collect topic:{}",data);
			//}
    	}
        break;
			
        case 3001:
        {
            signalRuleInfo.eventid = CSMAP_3;
            // signalRuleInfo.collectDatas.push_back("ad_algo_ins-localization.InsData-OpenSourceDu");
            //signalRuleInfo.collectDatas.push_back("ad_algo_ins-localization.InsData-OpenSourceDuSparse");
			std::shared_ptr<ProtoCondInfo_t> BA626ProtoCondInfo = std::make_shared<ProtoCondInfo_t>();
			Log_Info("gd fence type normal map collect :{}",type);
			if(DcAdr::AdrTrigger::getInstance().getOneEventProtoCondInfo(CSMAP_3,BA626ProtoCondInfo))
			{
				Log_Info("gd get {} collect success:{}",CSMAP_3,type);
			}
			
			signalRuleInfo.collectDatas =BA626ProtoCondInfo->collectData;
			Log_Info("gd BA626 collect topic.size:{}",signalRuleInfo.collectDatas.size());
			//for(auto data:signalRuleInfo.collectDatas)
			//{
			//	Log_Info("gd BA626 collect topic:{}",data);
			//}
    	}
        break;
			
        default:
            Log_Info("fence type not define:{}",type);
            break;
        }
        if(!to_string(type).empty())
        {
            if( to_string(type)[0] == '4')
            {
                //gd map_collect 4001
                global_data::g_normal_collect__filename.clear();
                std::shared_ptr<ProtoCondInfo_t> mapProtoCondInfo = std::make_shared<ProtoCondInfo_t>();
                signalRuleInfo.eventid= CSMAP_4;
                Log_Info("gd fence type normal map collect :{}",type);
                if(DcAdr::AdrTrigger::getInstance().getOneEventProtoCondInfo(CSMAP_4,mapProtoCondInfo))
                {
                    Log_Info("gd get {} collect success:{}",CSMAP_4,type);
                }
                
                signalRuleInfo.collectDatas =mapProtoCondInfo->collectData;
                for(auto data:signalRuleInfo.collectDatas)
                {
                    Log_Info("gd ba802 collect topic:{}",data);
                }
                global_data::g_normal_collect__fenceType=to_string(type);
            }
        }
        signalRuleInfo.id = "";
        if (fences[i].isMember("id"))
        {
            signalRuleInfo.id = JsonToValue<std::string>(fences[i]["id"]);
        }

        int timeout = 0;
        if (fences[i].isMember("timeOut"))
        {
            timeout = JsonToValue<int>(fences[i]["timeOut"]) * 1000;//转出ms
        }

        if (timeout == 0)//0:无限，转化为1小时
        {
            timeout = 1*60*60 *1000;
        }
        signalRuleInfo.tiemout = timeout;     

        if (!fences[i].isMember("geom"))
        {
            continue;
        }
        string wkt = JsonToValue<std::string>(fences[i]["geom"]);
        if (wkt.empty())
        {
            Log_Info("fences[{}] geom is empty", i);
            continue;
        }

        signalRuleInfo.geom_polygon =  readerPoint->read(wkt);
        if (signalRuleInfo.geom_polygon == nullptr)
        {
            Log_Info("get wkt faild;");
        }
        else
        {
            v_Fences.push_back(signalRuleInfo);
            Log_Info("inser one fence; type:{} id :{}",signalRuleInfo.type, signalRuleInfo.id);
        }
    }
    isConfigLoad = true;
    return true;
}
void MapCollect::SetSpeed(const string &data)
{
    BusespProto::BusEsp tmp;
    if (!tmp.ParsePartialFromArray(data.data(), data.size()))
    {
        Log_Info("pare proto BusespProto::BusEsp error!");
        return;
    }

    m_spd =  tmp.esp_motion_info().esp_veh_spd();
    // Log_Info("zjs_tmp_todel; m_spd:{}", m_spd);

}

bool MapCollect::GetCsmapTimeFromFile(const string &filename, uint64_t &begtime, uint64_t &endtime)
{
    bool ret = false;
    string filename_pre = filename.substr(0, filename.find_last_of("."));
    vector<string> tmp = CommonOprString::splitbypattern(filename_pre, "_");

    if (tmp.size() == 5)
    {
        begtime = stoull(tmp.at(3));
        endtime = stoull(tmp.at(4));

        ret = true;
    }

    return ret;
}

bool MapCollect::CsmapCollectFinish(uint64_t firstInTime_csmap, uint64_t OutTime_csmap, std::vector<TrigerFile> &otherSysFile)
{
/*
    /map/csmap/upload/
    VEC_result_1_1715594651567100_171559465156710  VEC_result_1_{开始utc时间}_{结束utc时间}  

root@tegra-ubuntu:/map/csmap/upload# ls
VEC_result_1_1718451229024200_1718451499633400.zip
VEC_result_1_1718451499633400_1718451578636200.zip
VEC_result_1_1718451578636200_1718451644838300.zip
VEC_result_1_1718451644838300_1718451760908600.zip
VEC_result_1_1718451760908600_1718451856312800.zip
VEC_result_1_1718452721778800_1718453204797100.zip
VEC_result_1_1718602893923000_1718603040728200.zip
VEC_result_1_1718603040728200_1718603130197500.zip
VEC_result_1_1718603130197500_1718603203900300.zip
VEC_result_1_1718603203900300_1718603510646600.zip
VEC_result_1_1718603510646600_1718603593016800.zip
VEC_result_1_1718603699820099_1718607546970700.zip
VEC_result_1_1718624451702800_1718624793850000.zip
VEC_result_1_1718624793850000_1718624885953700.zip
VEC_result_1_1718624885953700_1718624976624199.zip
VEC_result_1_1718624976624199_1718625119763200.zip
VEC_result_1_1718625119763200_1718625282469600.zip
VEC_result_1_1718625379073200_1718625875793400.zip
VEC_result_1_1718667893658700_1718668093396200.zip
VEC_result_1_1718668093396200_1718668210399200.zip
VEC_result_1_1718668210399200_1718668329869399.zip
VEC_result_1_1718668329869399_1718668389371800.zip
VEC_result_1_1718668389371800_1718668447706400.zip
VEC_result_1_1718668447706400_1718669003990300.zip  

m_csmap_time = 1717743850 * 1000000 = 1717743850000000;
1717743850000000
1718668447706400
*/
    bool finish = false;
    string folderPath = "/map/csmap/upload/";
    DIR *dir = opendir(folderPath.c_str());
    if (NULL == dir)
    {
        Log_Info("目录文件:{}  打开失败!!!", folderPath);
        return true;
    }

    struct dirent *dir_info;
    //struct stat s_buf;

    std::string absPath = "";
    while ((dir_info = readdir(dir)))
    {
        string fileName = dir_info->d_name;
        uint64_t begtime = 0;
        uint64_t endtime = 0;
        if ((fileName.find("VEC_result_") != string::npos) && GetCsmapTimeFromFile(fileName, begtime, endtime))
        {
            Log_Info("zjs_tmp_ditu; shiliang_file: {} begtime:{} endtime:{} ddd firstInTime_csmap:{} OutTime_csmap:{}", fileName, begtime, endtime, firstInTime_csmap, OutTime_csmap);

            if (endtime > OutTime_csmap)//只要其中一个文件的结束时间比出围栏时间大，说明矢量数据文件已经录制完成
            {
                finish = true;
            }

            if ((endtime < firstInTime_csmap) || (begtime > OutTime_csmap))
            {
                continue;
            }
            TrigerFile oneSlFile;
            oneSlFile.controllerCode = global_data::g_controler_code;
            oneSlFile.fileName = folderPath + "/" + dir_info->d_name;
            otherSysFile.push_back(oneSlFile);
        }
    }

    closedir(dir);
    return finish;

}

//一类电子围栏判断；这类可能有多个围栏，只要一个触发了就跳过后面围栏的判断
bool MapCollect::OneTypeFenceJudge(const uint8_t &inoutStatus, std::vector<FenceInfo_t>::iterator &it, std::vector<FenceInfo_t> &fences)
{
    bool fenceHpen = true;
    bool deletOne = false;

    switch (it->status)
    {
    case FenceStatus::FENCE_INVALID:
    {
        if ((inoutStatus == 1) && (m_spd > 0)) //首次进入s
        {
                        
            if(!it->eventid.compare(CSMAP_4))
            {
                Log_Info("gd FENCE  BA802 ID : {} ",it->id);
                auto nowtime = CommonOprTime::getTime();
                //if(CSMAP_4_Collect_fin_time != 0)
                if (std::abs(CSMAP_4_Collect_fin_time) >= mapEpsilon)
                {
                    if (nowtime - CSMAP_4_Collect_fin_time < 30*60 *1000) 
                    {
                        Log_Info("gd uploading BA802 ");
                        Log_Info("gd nowtime : {} collect_fin_time {} nowtime - collect fin time : {}",nowtime,CSMAP_4_Collect_fin_time,nowtime-CSMAP_4_Collect_fin_time);
                        break;
                    }
                }   
                
            }
            it->status = FenceStatus::FENCE_FIRSTIN;
        }
        else
        {
            fenceHpen = false;
        }        

        break;
    }
    case FenceStatus::FENCE_FIRSTIN:
    {
        TriggerEventInfo trigger;
        trigger.triggerTime = Util::getMsTime();
        trigger.recordTime = CommonOprTime::getTime();
        Log_Info("first in fence;type:{}, id:{}, getTime:{}", it->type, it->id, trigger.recordTime);

        trigger.beforeTime = 1000.0;
        trigger.laterTime = 3 * 1000.0;
        trigger.eventName = it->eventid;
        trigger.collectDatas = it->collectDatas;
        trigger.timeout = it->tiemout;
        trigger.triggerStartTime =KTime::getPubTime();
        DataCache::getInstance().acquireDataToSave(trigger);

        it->status = FenceStatus::FENCE_IN;
        it->firstInTime = trigger.recordTime;
        it->firstInTime_csmap = m_csmap_time;       
        break;
    }
    case FenceStatus::FENCE_IN:
    {
        auto nowtime = CommonOprTime::getTime();
        if (nowtime - it->firstInTime > it->tiemout) //超时，认为此次采集无效。重新采集
        {
            if(!it->eventid.compare(CSMAP_4))
            {
                it->OutTime_csmap = m_csmap_time;
                it->status = FenceStatus::FENCE_OUT;
                CSMAP_4_Collect_fin_time = CommonOprTime::getTime();
                Log_Info("gd fence TIME collect fanish; nowtime: {} firstInTime: {} tiemout: {} collect fin time {} ", nowtime, it->firstInTime, it->tiemout,CSMAP_4_Collect_fin_time);
                break;  
            }
            Log_Info("fence timeout; nowtime: {} firstInTime: {} tiemout: {}", nowtime, it->firstInTime, it->tiemout);
            //采集无效，删除
            DataCache::getInstance().endEvent(it->eventid);
            it->status = FenceStatus::FENCE_INVALID;
        }
        else if (inoutStatus == 2)
        {
            it->OutTime_csmap = m_csmap_time;
            it->status = FenceStatus::FENCE_OUT;
            if(!it->eventid.compare(CSMAP_4))
            {
                CSMAP_4_Collect_fin_time = CommonOprTime::getTime();
                Log_Info("gd fence OUT collect fanish; nowtime: {} firstInTime: {} tiemout: {} collect fin time {} ", nowtime, it->firstInTime, it->tiemout,CSMAP_4_Collect_fin_time);
            }
        }
        else
        {
            TriggerEventInfo trigger;
            trigger.triggerTime = Util::getMsTime();
            trigger.recordTime = CommonOprTime::getTime();
            trigger.beforeTime = 1000.0;
            trigger.laterTime = 3000.0;
            trigger.eventName = it->eventid;
            trigger.collectDatas = it->collectDatas;
            trigger.timeout = it->tiemout;
            trigger.triggerStartTime =KTime::getPubTime();
            DataCache::getInstance().acquireDataToSave(trigger);
        }

        break;
    }
    case FenceStatus::FENCE_OUT://正常出围栏结束的
    {
        // if (it->type == 1000) //1.0等待矢量数据采集完毕
        // {
        //     std::vector<TrigerFile> otherVec;
        //     if (CsmapCollectFinish(it->firstInTime_csmap, it->OutTime_csmap, otherVec))
        //     {
        //         /*事件信息组装矢量数据，删此电子围栏*/
        //         TriggerEventInfo trigger;
        //         trigger.triggerTime = Util::getMsTime();
        //         trigger.recordTime = CommonOprTime::getTime();
        //         trigger.beforeTime = 1000.0;
        //         trigger.laterTime = 1000.0;
        //         trigger.eventName = it->eventid;

        //         trigger.otherSysFile = otherVec;
        //         trigger.timeout = it->tiemout;
        //         DataCache::getInstance().acquireDataToSave(trigger);

        //         MapCollect::getInstance().deletFenceConfig(it->id);//认为采集有效，删配置下次不采 
        //         it = fences.erase(it);
        //         deletOne = true;
        //         Log_Info("1000 weilan have Csmap_shiliang_data;");
        //     }
        //     else if ((m_csmap_time - it->OutTime_csmap) > (2*60*100))//离开围栏120s后还是没有矢量数据;删除此围栏
        //     {
        //         MapCollect::getInstance().deletFenceConfig(it->id);//认为采集有效，删配置下次不采 
        //         it = fences.erase(it);
        //         deletOne = true;
        //         Log_Info("1000 weilan; no Csmap_shiliang_data");
        //     }
        // }
        // else
        {
            MapCollect::getInstance().deletFenceConfig(it->id);//认为采集有效，删配置下次不采 
            it = fences.erase(it);
            deletOne = true;
            Log_Info("fence out weilan;delet; firstInTime_csmap:{} OutTime_csmap:{}", it->firstInTime_csmap, it->OutTime_csmap);
        }
        break;
    }
    default:
    {
        break;
    }
    }

    if (!deletOne)
    {
        it++;
    }

    return fenceHpen;
}


bool MapCollect::IsValid(const double &lon, const double &lat)
{
    return lon > 0 || lat > 0;
}

void MapCollect::mapEventhappen(const std::string &topic, const string &data, const double &time)
{
    (void)time;
    if (!isConfigLoad)
    {
        return;
    }

    localization::InsData gpsData;
    if (gpsData.ParsePartialFromArray(data.data(), data.size()))
    {
        double lon = gpsData.longitude(); //106.7628659397
        double lat = gpsData.latitude();  //29.6382739258
   
        if (!IsValid(lon, lat))
        {
            return;
        }        

        m_csmap_time = gpsData.utc() * 1000000;//utc时间时到s

        for (auto beg = m_eventFence.begin(); beg != m_eventFence.end();beg++)//1000/2001/3001 各类围栏判断
        {
            std::vector<FenceInfo_t> &fences = beg->second;
            std::vector<FenceInfo_t>::iterator it = fences.begin();            
            for (; it != fences.end();)//某类中多个围栏判断
            {
                uint8_t inoutStatus = 0;
                if (InsidePolygonWkt(lon, lat, it->geom_polygon))//在电子围栏内
                {
                    inoutStatus = 1;
                }
                else
                {
                    inoutStatus = 2;
                }

                //Log_Info("zjs_tmp_ditu; inoutStatus:{}, type:{}, id:{}", inoutStatus, it->type, it->id);

                if (OneTypeFenceJudge(inoutStatus, it, fences))//一类围栏中的某个触发了，跳过同类型其他围栏的检查
                {
                    break;
                }
            }
        }
    }
    else
    {
        Log_Info("GpsData parse proto data failed , topic: {}", topic);
    }
}

bool MapCollect::InsidePolygonWkt(double &lon,  double &lat, const std::shared_ptr<geos::geom::Geometry> &geom_polygon) 
{
  geos::geom::Coordinate wkt_odometry(lon, lat);
  geos::geom::Point *odometry_p = factory->createPoint(wkt_odometry);

  return geom_polygon->contains(odometry_p);
};


